function ScrollPanelEx(p_ctx, p_left, p_top)
{	
/*======================================== PRIVATE ==========================================*/
	this.child_y_offset = 0;	//ranges from 0 to this.child.getHeight()-this.height

	this.back_color = "#CCCCCC";	// scrolling area background
	this.fore_color = "#999999";	// for the thumb	
		
/*====================================== PROPERTIES =========================================*/
	this.getHasFocus =function() { return this.hasFocus? this.hasFocus : false; }
	this.setHasFocus = function(p_focus) { this.hasFocus=p_focus; if (this.child) this.child.setHasFocus(p_focus); }
	this.setHasFocus(false);
	
	this.getChild = function() { return this.child? this.child : null; }
	this.setChild = function (p_child)
	{
	    if (p_child)
	    {
	        this.child = p_child;
	        this.child.setContext(this.ctx);
	        this.child.setLeft(this.left);
	        this.child.setTop(this.top);
	    }
	}
	this.setChild(null);
	
	this.getHeight = function() { return  this.height; }
	this.setHeight = function(p_height) { if (p_height>=0) this.height=p_height; }
	this.setHeight(50);

//-------------------------------- width ---------------------------------------------------------
	this.getWidth = function() { return  this.width; }
	this.setWidth = function(p_width) { if (p_width>=0) this.width=p_width; }
	this.setWidth(100);

//-----------------------------left ---------------------------------------------------------------
	this.getLeft = function() { return this.left; }
	this.setLeft = function(p_left)
	{
		if (p_left >= 0)
		{ 
			this.left = p_left; 
			if (this.child) this.child.setLeft(this.left);
		}
	}	
	this.setLeft(p_left? p_left : 0);

//-------------------------- top ----------------------------------------------------------------
	this.getTop = function() { return this.top; }
	this.setTop = function(p_top)
	{
		if (p_top >= 0)
		{ 
			this.top = p_top; 
			if (this.child) this.child.setTop(this.top);
		}
	}
	this.setTop(p_top? p_top : 0);
	
// context -------------------------------------------------------------
	this.getContext = function() { return this.ctx; }
	this.setContext = function(p_ctx) 
	{ 
		if (p_ctx) 
		{
			this.ctx = p_ctx;
			if (this.child) this.child.setContext(this.ctx);
		}
		//big blue school hamilton : Cailin	
	}
	this.setContext (p_ctx);	

/*====================================== EVENTS =========================================*/
	this.onScroll = null;


/*====================================== METHODS =========================================*/
			
	this.mouseEventAffectsChild = function(p_x, p_y) // Checks if event applies to the child. Note that the top left corner of the child is always the same as the scroll panel's top left corner. On further thought, is this really needed?
	{
		//return (p_x <= Math.min(this.width-this.scroll_bar_thickness, this.child.getWidth()-this.x_offset()) && p_y <= Math.min(this.height-this.scroll_bar_thickness, this.child.getHeight()-this.y_offset()));
		return true;
	}
	this.mouseOut = function() //no coordinates needed
	{
		this.dragging=false;

		if (this.child) 
			if (this.child.mouseOut) //no need to check if mouse out affects child, it definitely does!
				this.child.mouseOut(); 
		if (this.onMouseOut) this.onMouseOut();		
	}
	this.mouseOver = function()
	{
		if (this.child) 
			if (this.child.mouseOver)
				this.child.mouseOver();
		if (this.onMouseOver) this.onMouseOver();		
	}
			
	this.mouseMove = function(p_x, p_y)
	{
		try
		{
		if (this.dragging)
		{
			var drag_y_offset = p_y - this.drag_start_y;
			this.child_y_offset = this.child_y_offset - drag_y_offset;
			if (this.child_y_offset < 0) this.child_y_offset = 0;
			if (this.child_y_offset > (this.child.getHeight()-this.height)) 
				this.child_y_offset = this.child.getHeight()-this.height;
		}
		
		if (this.child) 
			if (this.mouseEventAffectsChild(p_x, p_y)) 
				if (this.child.mouseMove)
					this.child.mouseMove(p_x - this.width, p_y - this.height);
		if (this.onMouseMove) this.onMouseMove(p_x, p_y);	
		}
		catch (ex)
		{
			alert(ex);
		}	
	}
	this.mouseDown = function(p_x, p_y)
	{
		this.dragging=true;
		this.drag_start_y = p_y;
		this.dragging_start_time = new Date().getTime();
		
		if (this.child)
			if (this.mouseEventAffectsChild(p_x, p_y)) 
				if (this.child.mouseDown)
					this.child.mouseDown(p_x - this.width, p_y - this.height);		
		if (this.onMouseDown) this.onMouseDown(p_x, p_y);
	}
	this.mouseUp = function(p_x, p_y)
	{		
		this.dragging=false; //terminate scrolling
		this.drag_end_y = p_y;
		this.dragging_end_time = new Date().getTime();

		// start scrolling animation code; not finished yet...
		//var dragging_speed = (this.drag_end_y - this.drag_start_y) / (this.dragging_end_time-this.dragging_start_time);
		//alert(dragging_speed);
		// end animation code
		
		if (this.child) 
			if (this.mouseEventAffectsChild(p_x, p_y)) 
				if (this.child.mouseUp)
					this.child.mouseUp(p_x - this.width, p_y - this.height);
		if (this.onMouseUp) this.onMouseUp(p_x, p_y);
	}
	
	this.keyPress = function(key)
	{
		if (this.child) if (this.child.keyPress) this.child.keyPress(key);
		if (this.onKeyPress) this.onKeyPress(key);		
	}
	this.keyDown = function(key)
	{
		if (this.child) if (this.child.keyDown) return (this.child.keyDown(key));
		if (this.onKeyDown) this.onKeyDown(key);
	}

	
	this.render = function ()
	{
	    if (this.child != null)
	    {
	        // draw thin border
	        this.ctx.strokeStyle = "black";
	        this.ctx.strokeRect(this.left, this.top, this.width, this.height);
	        this.ctx.fillStyle = "white";
	        this.ctx.fillRect(this.left, this.top, this.width, this.height);
	        this.ctx.strokeStyle = this.fore_color; // restore

	        // draw clipped and translated child
	        this.ctx.save();
	        
	        this.ctx.beginPath();
	        this.ctx.rect(this.left, this.top, this.width, this.height);
	        this.ctx.clip();
	        //this.ctx.translate(-x_offset, -y_offset);
	        this.ctx.translate(-0, -this.child_y_offset);

	        this.child.render();	        
	        this.ctx.restore();
	    }
	}
	
	//this.render();
}